x86-64/MMCFG: finally make Fam10 enabling work
authorJan Beulich <jbeulich@novell.com>
Mon, 25 Jul 2011 15:42:53 +0000 (16:42 +0100)
committerJan Beulich <jbeulich@novell.com>
Mon, 25 Jul 2011 15:42:53 +0000 (16:42 +0100)
Forcibly enabling the MMCFG space on AMD Fam10 CPUs cannot be expected
to work since with the firmware not being aware of the address range
used it cannot possibly reserve the space in E820 or ACPI resources.
Hence we need to manually insert the range into the E820 table, and
enable the range only when the insertion actually works without
conflict.

Further, the actual enabling of the space is done from identify_cpu(),
which means that acpi_mmcfg_init() muts be called after that function
(and hance should not be called from acpi_boot_init()). Otherwise,
Dom0 would be able to use MMCFG, but Xen wouldn't.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/acpi/boot.c
xen/arch/x86/e820.c
xen/arch/x86/setup.c
xen/arch/x86/x86_32/pci.c
xen/arch/x86/x86_64/mmconf-fam10h.c
xen/include/asm-x86/e820.h

index f6309a6e921445dfa8272fe855770bd7b50561df..6262dac9d9d943eacee0ef6f1f34df5fccbfd735 100644 (file)
@@ -832,8 +832,6 @@ int __init acpi_boot_init(void)
 
        acpi_dmar_init();
 
-       acpi_mmcfg_init();
-
        erst_init();
 
        return 0;
index a29a153c545ad2360b566ec1da730149ee3dccd9..1697e770c2ed84c548f1e64cf1178d54e81abd52 100644 (file)
@@ -563,6 +563,55 @@ static void __init machine_specific_memory_setup(
         clip_to_limit(top_of_ram, "MTRRs do not cover all of memory.");
 }
 
+/* This function relies on the passed in e820->map[] being sorted. */
+int __init e820_add_range(
+    struct e820map *e820, uint64_t s, uint64_t e, uint32_t type)
+{
+    unsigned int i;
+
+    for ( i = 0; i < e820->nr_map; ++i )
+    {
+        uint64_t rs = e820->map[i].addr;
+        uint64_t re = rs + e820->map[i].size;
+
+        if ( rs == e && e820->map[i].type == type )
+        {
+            e820->map[i].addr = s;
+            return 1;
+        }
+
+        if ( re == s && e820->map[i].type == type &&
+             (i + 1 == e820->nr_map || e820->map[i + 1].addr >= e) )
+        {
+            e820->map[i].size += e - s;
+            return 1;
+        }
+
+        if ( rs >= e )
+            break;
+
+        if ( re > s )
+            return 0;
+    }
+
+    if ( e820->nr_map >= ARRAY_SIZE(e820->map) )
+    {
+        printk(XENLOG_WARNING "E820: overflow while adding region"
+               " %"PRIx64"-%"PRIx64"\n", s, e);
+        return 0;
+    }
+
+    memmove(e820->map + i + 1, e820->map + i,
+            (e820->nr_map - i) * sizeof(*e820->map));
+
+    e820->nr_map++;
+    e820->map[i].addr = s;
+    e820->map[i].size = e - s;
+    e820->map[i].type = type;
+
+    return 1;
+}
+
 int __init e820_change_range_type(
     struct e820map *e820, uint64_t s, uint64_t e,
     uint32_t orig_type, uint32_t new_type)
index c2a2aaab564226a2285180781c220fd72389024b..83d59025d128b908370c44479ace0a5dc7de82fd 100644 (file)
@@ -1248,6 +1248,8 @@ void __init __start_xen(unsigned long mbi_p)
 
 #ifdef CONFIG_X86_64
     vesa_mtrr_init();
+
+    acpi_mmcfg_init();
 #endif
 
     if ( opt_nosmp )
index 1f77ebc835f66558fe535b46cadb8e09b7d48e67..6bc61185c3c110602b52e77d040d8a29fe1681a2 100644 (file)
@@ -60,8 +60,3 @@ int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
 {
     return 0;
 }
-
-void acpi_mmcfg_init(void)
-{
-    return;
-}
index d8c29ba72bb79b9cf62c59225e89ef01ba51eb97..bd06f2b0cd7cbd817c786ba0f582c597a4d9199c 100644 (file)
@@ -9,6 +9,7 @@
 #include <xen/init.h>
 #include <xen/dmi.h>
 #include <asm/amd.h>
+#include <asm/e820.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
 
@@ -131,7 +132,8 @@ static void __init get_fam10h_pci_mmconf_base(void)
        return;
 
 out:
-       fam10h_pci_mmconf_base = start;
+       if (e820_add_range(&e820, start, start + SIZE, E820_RESERVED))
+               fam10h_pci_mmconf_base = start;
 }
 
 void __cpuinit fam10h_check_enable_mmcfg(void)
index d0486ae7c5d1c3270d4de93ceb15b5dc80786ec6..0fd81f6a0f4c6fb64eaa0e6bd3a69dc1a204d1e2 100644 (file)
@@ -28,6 +28,8 @@ extern int reserve_e820_ram(struct e820map *e820, uint64_t s, uint64_t e);
 extern int e820_change_range_type(
     struct e820map *e820, uint64_t s, uint64_t e,
     uint32_t orig_type, uint32_t new_type);
+extern int e820_add_range(
+    struct e820map *, uint64_t s, uint64_t e, uint32_t type);
 extern unsigned long init_e820(const char *, struct e820entry *, int *);
 extern struct e820map e820;